package com.skp.shaphan.ui.results;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;

import javax.swing.table.AbstractTableModel;

import com.skp.job.ProjectJobException;

/**
 * A table model for the ResultsTable
 * @author Stephen Phillips
 *
 */
public class ResultsModel extends AbstractTableModel {
	private ResultSet results;
	private Vector<ResultsCell[]> data;
	private boolean finishedLoading;
	private static final int INITIAL_ROW_MAX = 50;
	/**
	 * Track the biggest length in characters for each column for
	 * formatting purposes.
	 */
	private Integer[] maxLengths;
	
	public ResultsModel() {
		results = null;
		finishedLoading = true;
	}

	public void setResultSet(ResultSet results) {
		// close the old results
		if(this.results != null) {
			try {
				Statement statement = this.results.getStatement();
				this.results.close();
				if(statement != null) {
					statement.close();
				}
			} catch (SQLException e) {
				ProjectJobException.displayException(e);
			}
		}
		this.results = results;
		// for going back to no results
		if(results == null) {
			finishedLoading = true;
			this.fireTableStructureChanged();
			return;
		}
		
		finishedLoading = false;
		data = new Vector<ResultsCell[]>();
		try {
			//System.out.println("Row: " + results.getRow());
			System.out.println("Type = " + results.getType());
			ResultSetMetaData md = results.getMetaData();
			
			
			// get the number of columns to loop through them
			int columnCount = results.getMetaData().getColumnCount();
			
			// initialize the max lengths
			maxLengths = new Integer[columnCount];
			for(int x=0; x<columnCount; x++) {
				maxLengths[x] = new Integer(0);
			}
			
			// declare variables before the loop
			int length = 0;
			ResultsCell cell;
			boolean broke = false;
			while(results.next()) {
				ResultsCell[] row = new ResultsCell[columnCount];
				for(int x=1; x<=columnCount; x++) {
					cell = new ResultsCell(results, x);
					row[x-1] = cell;
					// calculate lengths
					length = cell.getFontMetrics(cell.getFont()).stringWidth(cell.getText());
					if(length > maxLengths[x-1].intValue()) {
						maxLengths[x-1] = new Integer(length);
					}
				}
				data.add(row);
				if(data.size() >= INITIAL_ROW_MAX) {
					broke = true;
					break;
				}
			}
			if(!broke) {
				finishedLoading = true;
			}
		} catch (SQLException e) {
			(new ProjectJobException(e)).displayException();
		} catch (IOException e) {
			(new ProjectJobException(e)).displayException();
		}
		this.fireTableStructureChanged();
	}

	/**
	 * Loads more rows into the model.
	 */
	public void loadMoreRows() {
		int rowStart = data.size() + 1;
		int loadCount = 0;
		try {
			// get the number of columns to loop through them
			int columnCount = results.getMetaData().getColumnCount();

			
			// declare variables before the loop
			int length = 0;
			ResultsCell cell;
			boolean broke = false;
			while(results.next()) {
				ResultsCell[] row = new ResultsCell[columnCount];
				for(int x=1; x<=columnCount; x++) {
					cell = new ResultsCell(results, x);
					row[x-1] = cell;
					// calculate lengths
					length = cell.getFontMetrics(cell.getFont()).stringWidth(cell.getText());
					if(length > maxLengths[x-1].intValue()) {
						maxLengths[x-1] = new Integer(length);
					}
				}
				data.add(row);
				loadCount++;
				if(loadCount >= INITIAL_ROW_MAX) {
					broke = true;
					break;
				}
			}
			if(!broke) {
				finishedLoading = true;
			}
		} catch (SQLException e) {
			(new ProjectJobException(e)).displayException();
		} catch (IOException e) {
			(new ProjectJobException(e)).displayException();
		}
		//this.fireTableStructureChanged();
		if(loadCount > 0) {
			this.fireTableRowsInserted(rowStart, rowStart + loadCount);
		}
	}

	@Override
	public int getColumnCount() {
		if(results == null) {
			return 1;
		} else {
			try {
				return results.getMetaData().getColumnCount();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				throw new Error("SQL Error: " + e.getLocalizedMessage(), e);
			}
		}
	}

	@Override
	public int getRowCount() {
		if(results == null) {
			return 1;
		} else {
			return data.size();
		}
	}
	
	public int getRowsLoaded() {
		if(results == null) {
			return 0;
		} else {
			return data.size();
		}
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		if(results == null) {
			return new ResultsCell();
		} else {
			if(data.size() <= rowIndex) {
				// Empty Result Set
				return new ResultsCell();
			} else {
				return data.get(rowIndex)[columnIndex];
			}
		}
	}

	@Override
	public Class<?> getColumnClass(int columnIndex) {
		return ResultsCell.class;
	}
	
	public int getMaxCharacterLength(int columnIndex) {
		if(maxLengths == null) {
			return 0;
		}
		return maxLengths[columnIndex].intValue();
	}

	public boolean isFinishedLoading() {
		return finishedLoading;
	}
	
	public boolean hasResults() {
		return !(results == null);
	}

	public ResultSet getResultSet() {
		return results;
	}

}
